package game.leon.engine.script;

import game.leon.engine.script.exec.Chunk;
import game.leon.engine.script.exec.Var;
import game.leon.engine.utils.LinkedNode;
import org.apache.log4j.Logger;

import static game.leon.engine.script.Parser.Def.*;

/**
 * 关键 部分来了, 生成字节码
 * 然后as端, .net端, 都只要写个执行环境就ok了
 * 指令设计一下, 其他就单元测试搞定
 * User: bianpeng
 * Date: 12-2-3
 */
public class Compiler {
    private Logger logger = Logger.getLogger(getClass());
    private Token tree;
    private Chunk chunk;
    public Compiler(Token tree) {
        this.tree = tree;
        this.chunk = new Chunk();
    }
    public Chunk compile() {
        compileChunk(tree);
        return new Chunk();
    }
    private void compileChunk(Token token) {
        assert TOKEN_CHUNK == token.getType();
        LinkedNode<Token> node = token.child;
        while (node != null) {
            compileFrame(node.getItem());
            node = node.getNext();
        }
    }
    private void compileFrame(Token frame) {
        assert TOKEN_FRAME == frame.getType();
        logger.info("start frame");
        LinkedNode<Token> node = frame.sibling;
        while (node != null) {
            logger.info("push");
            compileForms(node.getItem());
            node = node.getNext();
        }
        logger.info("invoke");
    }
    //
    // 生成指令
    //
    private void compileForms(Token token) {
        LinkedNode<Token> node;
        switch (token.getType()) {
            case TOKEN_FRAME:
                compileFrame(token);
                break;
            case TOKEN_INT:
                logger.info("int:" + token.intVal);
                chunk.addConst(Var.integer(token.intVal));
                break;
            case TOKEN_NUM:
                logger.info("num:" + token.numVal);
                chunk.addConst(Var.number(token.numVal));
                break;
            case TOKEN_STR:
                logger.info("str:" + token.strVal);
                chunk.addConst(Var.string(token.strVal));
                break;
            case TOKEN_SYMBOL:
                logger.info("sym:" + token.strVal);
                chunk.addConst(Var.symbol(token.strVal));
                break;
            default:
                break;
        }
    }
}
